package com.zxl.live.tools.common;

import android.os.Looper;

import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 被观察者
 * Created by Administrator on 2016/7/4.
 */
// CHECKSTYLE:OFF
public abstract class Observable<S, F, C> implements Runnable {

    /**
     * 主线程
     */
    public static final int MAIN_THREAD = 1;

    /**
     * 当前线程
     */
    public static final int CURRENT_THREAD = 2;

    private int mCallBackType = MAIN_THREAD;

    private final ArrayList<Observer<S, F, C>> mObservers = new ArrayList<Observer<S, F, C>>();

    private static ExecutorService sExecutorService = Executors.newSingleThreadExecutor();

    /**
     * 开始模型数据处理
     */
    public Observable startDataHandle() {
        sExecutorService.execute(this);
        return this;
    }

    /**
     * 回调执行的线程
     * @param thread {@link Observable#MAIN_THREAD}, {@link Observable#CURRENT_THREAD}
     * @return
     */
    public Observable observerOn(int thread) {
        mCallBackType = thread;
        return this;
    }

    /**
     * 添加一个观察者
     * @param observer
     * @return
     */
    public Observable registerObserver(Observer<S, F, C> observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            if (!mObservers.contains(observer)) {
                mObservers.add(observer);
            }
        }
        return this;
    }

    /**
     * 移除一个观察者
     * @param observer
     */
    public void unregisterObserver(Observer<S, F, C> observer) {
        if (observer == null) {
            throw new IllegalArgumentException("The observer is null.");
        }
        synchronized(mObservers) {
            mObservers.remove(observer);
        }
    }

    /**
     * 移除所有的观察者
     */
    public void unregisterAll() {
        synchronized(mObservers) {
            mObservers.clear();
        }
    }

    /**
     * 处理结果失败
     * @param f
     */
    public void handleFail(F f) {
        handleObserver(new WorkerHelper(f, WorkerHelper.FLAG_FAIL));
    }

    /**
     * 处理结果成功
     * @param s
     */
    public void handleSuccess(S s) {
        handleObserver(new WorkerHelper(s, WorkerHelper.FLAG_Success));
    }

    /**
     * 处理结果完成
     * @param c
     */
    public void handleComplete(C c) {
        handleObserver(new WorkerHelper(c, WorkerHelper.FLAG_Complete));
    }

    private void handleObserver(WorkerHelper workerHelper) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            switch (mCallBackType) {
                case MAIN_THREAD:
                    workerHelper.run();
                    break;
                case CURRENT_THREAD:
                    ApplicationHelper.postThread(workerHelper);
                    break;
            }
        } else {
            switch (mCallBackType) {
                case MAIN_THREAD:
                    ApplicationHelper.postRunInUiThread(workerHelper);
                    break;
                case CURRENT_THREAD:
                    workerHelper.run();
                    break;
            }
        }
    }

    /**
     * 被观察者通知辅助类
     * @param <T>
     */
    private class WorkerHelper<T> implements Runnable {

        public static final int FLAG_FAIL = 1;

        public static final int FLAG_Success = 2;

        public static final int FLAG_Complete = 3;

        private T t;

        private int mFlag;

        public WorkerHelper(T t, int mFlag) {
            this.t = t;
            this.mFlag = mFlag;
        }

        @Override
        public void run() {
            synchronized (mObservers) {
                for (Observer observer : mObservers) {
                    switch (mFlag) {
                        case FLAG_FAIL:
                            observer.onFail(t);
                            break;
                        case FLAG_Success:
                            observer.onSuccess(t);
                            break;
                        case FLAG_Complete:
                            observer.onComplete(t);
                            break;
                    }
                }
            }
        }
    }
}
